/**********************************************************
 *
 *  Copyright (c) 2003  SeikoEpson Inc
 *  All Rights Reserved
 *
 *  File name :f_ldexp.c
 *  Function  :
 *        f_ldexp function returns a floating value which consists 
           given integer and fraction value.
 *        This file is copied from math.lib of 
 *                  CC33 tool(CC33v40.exe + CCPA45.exe, 
 *                  math of ansilib33v25 )
 *
 *  original file's Revision  :
 *      2000/02/10    first release                 M.Igarashi
 *  Revision  :
 *      2003/04/10    IrumaSoft M.Takeishi   1.st design
 *
 **********************************************************/
#include	<f_smcvals.h>
#include	<f_math.h>


// ALGORITHM
// 1.separate sfX into the fraction part as xfrac and into exponent part as wXexp   
// 2.caluculate exponent
//      wXexp = wXexp + dfX2
// 5.set exponent of xfrac
//

//  the architecture of float floating point
//
//   0 30         23 22                0  32 bit
//   -----------------------------------
//  | |   exponent  |  fraction         |
//   -----------------------------------
//  |               |                   |
//  |    8 bits     |    23 bits        |
//
//         bit    31         sign bit        (  1 bit  )
//             30 - 23      exponent part    (  8 bits )
//             22 -  0      fraction part    ( 23 bits )
//
//

float f_ldexp (float sfX, int sfX2){

	FLT_LNG	xfrac;
	unsigned long	ulHi;
	float sfRet;
	signed short	wXexp;


	xfrac._F=sfX;

	/* Is NaN, +-INF check */
	ulHi = 0x7f800000;
	if ( ( xfrac.st._LL & ulHi ) == ulHi ) {
		/* When sfX is +-INF, NaN */
		if ( ( xfrac.st._LL | 0x80000000 ) == f_N_INF.st._LL ) {
			/* +- INF */
			errno = ERANGE;
			sfRet = sfX;
		} else {
			/* NaN */
			errno = EDOM;
			sfRet = f_NAN._F;
		}
		return sfRet;
	}


	ulHi=xfrac.st._LL;

	wXexp=F_GET_EXP(ulHi)+sfX2;
	/* if x = 0 or result is so small, returns 0 */
	if ( wXexp < F_MIN_E || (ulHi & 0x7fffffff) == 0x00000000  ){				// too small
		sfRet=F_COPY_SIGN(0.0f ,sfX);
		return sfRet;
	}

	if((sfX2>2*F_B_FLT)||(wXexp > F_MAX_E)){
		errno	= ERANGE;
		if((ulHi&0x80000000) !=0){		//check arg
			sfRet=f_N_INF._F;
		}else{
			sfRet=f_P_INF._F;
		}
		return sfRet;
	}

	ulHi=F_EXP_PUT(F_MASK_EXPO(ulHi),wXexp);		// put expo
	xfrac.st._LL=ulHi;
	sfRet=xfrac._F;
	return sfRet;
}
